package cn.cicoding.mybatis.service.impl;

import cn.cicoding.mybatis.bean.GrateEntity;
import cn.cicoding.mybatis.bean.UserExcel;
import cn.cicoding.mybatis.mapper.ExcelUserMapper;
import cn.cicoding.mybatis.service.ExcelUserService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * created with IntelliJ IDEA.
 * author: cicoding
 * date: 2020/03/18
 * version: 1.0
 * description:
 */
@Service
public class ExcelExcelUserServiceImpl implements ExcelUserService {

    @Resource
    private ExcelUserMapper excelUserMapper;

    @Override
    public Object listAll(int page, int size) {
        PageHelper.startPage(page, size);
        List<UserExcel> userList = excelUserMapper.listAll();
        PageInfo<UserExcel> pageInfo = new PageInfo<>(userList);
        return pageInfo;
    }

    @Override
    public int insert() {
        long beforeTime = System.currentTimeMillis();
        int j = 0;
        for (int i = 0; i < 100000; i++) {
            UserExcel user = new UserExcel();
            user.setId(i);
            user.setUserName("张三" + i);
            user.setPassword(123456 + i + "");
            user.setPhone(13000000000L + i);
            user.setCreateTime(new Date());
            excelUserMapper.insert(user);
            j++;
        }
        long afterTime = System.currentTimeMillis();
        System.out.println("导入总耗时: "+ (afterTime - beforeTime));
        return j;
    }

    @Override
    public int remove(Integer userId) {
        return excelUserMapper.deleteUserById(userId);
    }

    @Override
    public int update(UserExcel user) {
        return excelUserMapper.update(user);
    }

    @Override
    public void downloadExcel(ServletOutputStream outputStream) {
        long beforeTime = System.currentTimeMillis();
        List<UserExcel> userList = excelUserMapper.listAll();
        for (UserExcel userExcel : userList) {

            // 这里模拟处理数据，实际上你可以进行更复杂的操作
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        long afterTime = System.currentTimeMillis();
        System.out.println("导出总耗时: "+ (afterTime - beforeTime) + "ms");
        EasyExcelFactory.write(outputStream, UserExcel.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("User").doWrite(userList);
    }

    @Override
    public void downloadMultithreadingExcel(ServletOutputStream outputStream) {
        long beforeTime = System.currentTimeMillis();
        List<UserExcel> userList = excelUserMapper.listAll();


        int dataSize = userList.size();
        int batchSize = 1000; // 每个线程处理的数据量大小
        int threadCount = (dataSize + batchSize - 1) / batchSize; // 计算所需线程数
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
        // 用于收集每个线程处理后的数据
        List<UserExcel> batchDataList = new ArrayList<>();

        // 提交任务到线程池
        for (int i = 0; i < threadCount; i++) {
            int fromIndex = i * batchSize;
            int toIndex = Math.min(fromIndex + batchSize, dataSize);
            List<UserExcel> batchData = userList.subList(fromIndex, toIndex);
            executorService.submit(() -> {
                for (UserExcel userExcel : batchData) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                // 然后将处理后的数据添加到共享列表
                batchDataList.addAll(batchData);
            });
        }


        // 关闭线程池，等待所有任务完成
        executorService.shutdown();
        while (!executorService.isTerminated()) {
            try {
                Thread.sleep(100); // 等待所有任务完成
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        long afterTime = System.currentTimeMillis();
        System.out.println("导出总耗时: "+ (afterTime - beforeTime) + "ms");
        EasyExcelFactory.write(outputStream, UserExcel.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("User").doWrite(batchDataList);
    }

    /**
     * 导出测试数据  多sheet
     * https://github.com/alibaba/easyexcel/blob/master/easyexcel-test/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java#L640C39-L640C75
     * @param outputStream
     */
    @Override
    public void downloadExcels(ServletOutputStream outputStream) {
        List<UserExcel> userList = excelUserMapper.listAll();
        List<GrateEntity> grateList = new ArrayList<>();
        GrateEntity grate1 = new GrateEntity();
        grate1.setGrate("一年级");
        grate1.setTeacher("班主任张三");
        grate1.setInstructor("李雷");
        grate1.setSubject("英语");
        grateList.add(grate1);

        GrateEntity grate2 = new GrateEntity();
        grate2.setGrate("二年级");
        grate2.setTeacher("班主任张三");
        grate2.setInstructor("李雷");
        grate2.setSubject("英语");
        grateList.add(grate2);

        GrateEntity grate3 = new GrateEntity();
        grate3.setGrate("三年级");
        grate3.setTeacher("班主任李四");
        grate3.setInstructor("王五");
        grate3.setSubject("数学");
        grateList.add(grate3);

        ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
        WriteSheet studentSheet = EasyExcel.writerSheet(0, "学生信息").head(UserExcel.class).build();
        WriteSheet grateSheet = EasyExcel.writerSheet(1, "班级信息").head(GrateEntity.class).build();
        excelWriter.write(userList, studentSheet).write(grateList, grateSheet);
        excelWriter.finish();
    }

    @Override
    public void upload(InputStream inputStream) throws IOException {

        List<UserExcel> cachedDataList = new ArrayList<>();

        // ReadListener不是必须的，它主要的设计是读取excel数据的后置处理(并考虑一次性读取到内存潜在的内存泄漏问题)
        EasyExcelFactory.read(inputStream, UserExcel.class, new ReadListener<UserExcel>() {

            @Override
            public void invoke(UserExcel user, AnalysisContext analysisContext) {
                cachedDataList.add(user);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                cachedDataList.forEach(user -> System.out.printf(user.toString()));
            }
        }).sheet().doRead();
    }


}
